{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_T4g3t5sLoag"
      },
      "source": [
        "# ZeroScript: AI-Powered Browser Test Automation using PraisonAI Agent & OpenAI"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "O4PKfpalLsmn"
      },
      "source": [
        "# Description"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CEG1pfumLysm"
      },
      "source": [
        "AI-powered browser testing using PraisonAI Agent and OpenAI. Executes YAML-defined test cases, captures screenshots, logs interactions, and generates JSON reports. Ideal for intelligent, automated UI testing.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lbgxOG4gL1Wf"
      },
      "source": [
        "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/DhivyaBharathy-web/PraisonAI/blob/main/examples/cookbooks/ZeroScript_AI_TestExecutor.ipynb)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WCJqMUzXIndh"
      },
      "source": [
        "# Dependencies"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "metadata": {
        "id": "9AQhJ59cJPmR"
      },
      "outputs": [],
      "source": [
        "!pip install --quiet praisonaiagents browser-use python-dotenv pyyaml openai\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QD-dF-6_It1z"
      },
      "source": [
        "# Environment Setup"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "QkRQDli4JhCV",
        "outputId": "4b8957ed-a37a-4b11-8585-3537a0437d40"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "True"
            ]
          },
          "execution_count": 35,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import os\n",
        "from dotenv import load_dotenv\n",
        "\n",
        "os.environ[\"OPENAI_API_KEY\"] = \"Enter your key\"  # replace with actual key\n",
        "load_dotenv()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ELuogWnrIw3o"
      },
      "source": [
        "# Create my_secrets.py"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "metadata": {
        "id": "sG6tO_v0Jm5N"
      },
      "outputs": [],
      "source": [
        "with open(\"my_secrets.py\", \"w\") as f:\n",
        "    f.write('''sensitive_data = {\n",
        "    \"username\": \"standard_user\",\n",
        "    \"password\": \"secret_sauce\"\n",
        "}''')\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rDB_viedIzRR"
      },
      "source": [
        "# Create views.py"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "metadata": {
        "id": "CtwcybdbJoV8"
      },
      "outputs": [],
      "source": [
        "with open(\"views.py\", \"w\") as f:\n",
        "    f.write('''\n",
        "from pydantic import BaseModel\n",
        "\n",
        "class TestResult(BaseModel):\n",
        "    status: str\n",
        "    message: str = \"\"\n",
        "''')\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YTRmBpTiI1kd"
      },
      "source": [
        "# Create agent.py"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "metadata": {
        "id": "zdJJGt6TJpvr"
      },
      "outputs": [],
      "source": [
        "with open(\"agent.py\", \"w\") as f:\n",
        "    f.write('''\n",
        "import os\n",
        "from praisonaiagents import Agent\n",
        "from browser_use import Browser, BrowserConfig, Controller\n",
        "from browser_use.browser.context import BrowserContext, BrowserContextConfig\n",
        "from openai import OpenAI\n",
        "from views import TestResult\n",
        "from my_secrets import sensitive_data\n",
        "\n",
        "# Browser setup\n",
        "browser = Browser(config=BrowserConfig(headless=True))\n",
        "context_cfg = BrowserContextConfig(save_recording_path=\"data/recordings\")\n",
        "controller = Controller(output_model=TestResult)\n",
        "\n",
        "async def browser_use(task: str):\n",
        "    context = BrowserContext(browser=browser, config=context_cfg)\n",
        "    agent = Agent(\n",
        "        task=task,\n",
        "        llm=OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"), model=\"gpt-4\"),\n",
        "        browser_context=context,\n",
        "        sensitive_data=sensitive_data,\n",
        "        controller=controller,\n",
        "        save_conversation_path=\"data/conversations/convo\",\n",
        "        extend_system_message=(\n",
        "            \"You are a professional software tester. Execute browser test steps precisely.\"\n",
        "        )\n",
        "    )\n",
        "    response = await agent.run()\n",
        "    await context.close()\n",
        "    return response\n",
        "''')\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-LZtQIE3I4-_"
      },
      "source": [
        "# Create Sample Test YAML"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "l1OdXYI-JreK",
        "outputId": "62323fcd-c74f-498f-defc-2c170fa8983e"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "350"
            ]
          },
          "execution_count": 39,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from pathlib import Path\n",
        "tests_dir = Path(\"tests\")\n",
        "tests_dir.mkdir(exist_ok=True)\n",
        "yaml_content = \"\"\"\n",
        "hooks:\n",
        "  beforeEach: |\n",
        "    Navigate to https://www.saucedemo.com\n",
        "  afterEach: |\n",
        "    Take screenshot\n",
        "\n",
        "tests:\n",
        "  - id: \"login_test_001\"\n",
        "    name: \"Valid Login Test\"\n",
        "    instructions: |\n",
        "      1. Enter standard_user in username field\n",
        "      2. Enter secret_sauce in password field\n",
        "      3. Click login button\n",
        "      4. Verify page contains text \"Products\"\n",
        "\"\"\"\n",
        "(Path(\"tests/login_test.yml\")).write_text(yaml_content)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sUjy-7OdI7p_"
      },
      "source": [
        "# Run Tests"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 40,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Agkiwh7xJtY3",
        "outputId": "759aa77c-fd65-49b8-b239-550588059478"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Exception ignored in: <function BrowserSession.__del__ at 0x7e2f540fb100>\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.11/dist-packages/browser_use/browser/session.py\", line 497, in __del__\n",
            "    status = f'\ud83e\ude93 killing pid={self.browser_pid}...' if (self.browser_pid and owns_browser) else '\u2620\ufe0f'\n",
            "                                                         ^^^^^^^^^^^^^^^^\n",
            "  File \"/usr/local/lib/python3.11/dist-packages/pydantic/main.py\", line 991, in __getattr__\n",
            "    raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\n",
            "AttributeError: 'BrowserSession' object has no attribute 'browser_pid'\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\u2705 Report saved to data/reports/report_20250630_092319.json\n"
          ]
        }
      ],
      "source": [
        "import asyncio, yaml, json, base64, shutil\n",
        "from agent import browser_use, browser\n",
        "from pathlib import Path\n",
        "from datetime import datetime\n",
        "\n",
        "# Clean or create data dirs\n",
        "for sub in [\"recordings\", \"conversations\", \"screenshots\", \"reports\"]:\n",
        "    d = Path(\"data\") / sub\n",
        "    if d.exists(): shutil.rmtree(d)\n",
        "    d.mkdir(parents=True, exist_ok=True)\n",
        "\n",
        "async def execute_test_file(path):\n",
        "    cfg = yaml.safe_load(Path(path).read_text())\n",
        "    hooks, results = cfg.get(\"hooks\", {}), []\n",
        "    for t in cfg[\"tests\"]:\n",
        "        task = f\"{hooks.get('beforeEach','')}\\n{t['instructions']}\\n{hooks.get('afterEach','')}\"\n",
        "        res = {\"id\": t[\"id\"], \"name\": t[\"name\"]}\n",
        "        try:\n",
        "            r = await browser_use(task)\n",
        "            imgs = r.screenshots()\n",
        "            if imgs:\n",
        "                out = Path(\"data/screenshots\") / f\"{t['id']}.png\"\n",
        "                out.write_bytes(base64.b64decode(imgs[-1]))\n",
        "            result_obj = r.final_result() if hasattr(r, \"final_result\") else str(r)\n",
        "            res[\"result\"] = result_obj.model_dump() if hasattr(result_obj, \"model_dump\") else str(result_obj)\n",
        "        except Exception as e:\n",
        "            res[\"error\"] = str(e)\n",
        "        results.append(res)\n",
        "    return results\n",
        "\n",
        "async def main():\n",
        "    all_results = []\n",
        "    for file in Path(\"tests\").glob(\"*.yml\"):\n",
        "        all_results.extend(await execute_test_file(str(file)))\n",
        "    report = Path(\"data/reports\") / f\"report_{datetime.now():%Y%m%d_%H%M%S}.json\"\n",
        "    report.write_text(json.dumps(all_results, indent=2))\n",
        "    await browser.close()\n",
        "    print(f\"\u2705 Report saved to {report}\")\n",
        "\n",
        "await main()\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}